package org.sunspotworld;

import com.sun.spot.sensorboard.peripheral.IAccelerometer3D;
//import com.sun.spot.sensorboard.peripheral.IAccelerometer3DThresholdListener;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ISwitch;
import com.sun.spot.sensorboard.peripheral.ISwitchListener;
import com.sun.spot.sensorboard.peripheral.ITriColorLED;
import com.sun.spot.sensorboard.peripheral.LEDColor;
import com.sun.spot.util.Utils;
import java.io.IOException;
import java.util.Random;

/**
 * 
 * @author Dani
 */
class Game implements ISwitchListener, Protocol, GameStates {

    private Main main;
    private ITriColorLED[] leds;
    private ISwitch leftSwitch;
    private ISwitch rightSwitch;
    private IAccelerometer3D accelerometer;

    //state
    private int currentState;
    private int oldState;
    
    //potatoe
    private long potatoe;
    private int potatoeLifetimeFactor;
    private int oldPotatoeLifetimeFactor;
    private long receiveTime;


    //score
    private int score;

    //gametimestamp
    private long gameTime;

    public Game(Main main) {
        this.main = main;
        leds = EDemoBoard.getInstance().getLEDs();
        leftSwitch = EDemoBoard.getInstance().getSwitches()[0];
        rightSwitch = EDemoBoard.getInstance().getSwitches()[1];
        accelerometer = EDemoBoard.getInstance().getAccelerometer();
        currentState = INITIAL;
        potatoe = 0;
        score = 0;
        oldState = 99;
        receiveTime = 0;
        potatoeLifetimeFactor = 10000;
        oldPotatoeLifetimeFactor = 99;
        gameTime = 0;
    }

    public void setGameTime(long gameTime) {
        score = 0;
        this.gameTime = System.currentTimeMillis() + gameTime;
    }

    public int getCurrentState() {
        return currentState;
    }

    public void setup() {
        leftSwitch.addISwitchListener(this);
        rightSwitch.addISwitchListener(this);
    }

    private void display() {
        if(oldState != currentState || oldPotatoeLifetimeFactor != potatoeLifetimeFactor){
            
            oldState = currentState;
            oldPotatoeLifetimeFactor = potatoeLifetimeFactor;

            resetLeds();
            Utils.sleep(1);//for the leds
        
        
            switch(currentState){
                case INITIAL:
                    for(int i = 0; i < leds.length; ++i) {
                    leds[i].setColor(LEDColor.BLUE);
                    leds[i].setOn();
                    }
                    break;
                case HASPOTATOE:
                    leds[2].setColor(LEDColor.YELLOW);
                    leds[2].setOn();
                    leds[3].setColor(LEDColor.YELLOW);
                    leds[3].setOn();
                    leds[4].setColor(LEDColor.YELLOW);
                    leds[4].setOn();
                    leds[5].setColor(LEDColor.YELLOW);
                    leds[5].setOn();
                    break;
                case WAITINGFORPOTATOE:
                    leds[0].setColor(LEDColor.CYAN);
                    leds[0].setOn();
                    leds[1].setColor(LEDColor.CYAN);
                    leds[1].setOn();
                    leds[6].setColor(LEDColor.CYAN);
                    leds[6].setOn();
                    leds[7].setColor(LEDColor.CYAN);
                    leds[7].setOn();
                    break;
                case CHOOSEPOTATOELIFETIME:
                    for(int i = 0; i<potatoeLifetimeFactor/10000;++i) {
                        leds[i].setColor(LEDColor.ORANGE);
                        leds[i].setOn();
                    }

                    for(int i = potatoeLifetimeFactor/10000; i < leds.length; ++i) {
                        leds[i].setColor(LEDColor.BLUE);
                        leds[i].setOn();
                    }
                    break;
                case LOSER:
                    for(int i = 0; i < leds.length; ++i) {
                        leds[i].setColor(LEDColor.RED);
                        leds[i].setOn();
                    }
                    break;
                case WINNER:
                    for(int i = 0; i < leds.length; ++i) {
                        leds[i].setColor(LEDColor.WHITE);
                        leds[i].setOn();
                    }
                    break;
                case WAIT:
                    for(int i = 0; i < leds.length; ++i) {
                        leds[i].setColor(LEDColor.BLUE);
                        leds[i].setOn();
                    }
                    break;
            }
        }
    }

    private void resetLeds() {
        for(int i = 0; i < leds.length; ++i) {
            leds[i].setOff();
        }
    }

    //gets called constantly so a seperate thread is not necessary
    public void update() {
        if(gameTime >= System.currentTimeMillis() || currentState == INITIAL || gameTime == 0) {
            if(main.getActiveConnections().size() == 0) {
                currentState = WINNER;
                score++;
                main.resetConnections();
                System.out.println("WINNER: " + score);
            } else {

                // Hold the potatoe for 2 seconds
                if(System.currentTimeMillis() - receiveTime > 2000){

                    String adress = generateRandomAdress();

                    if(currentState == HASPOTATOE && potatoe != 0) {
                        if(potatoe <= System.currentTimeMillis()) {
                            currentState = LOSER;
                            main.massMessage(DEADPLAYER+"");

                            if(main.getActiveConnections().size() > 1) {
                                potatoe = generatePotatoeLifeTime();
                                main.sendConnectionMessage(POTATOE + " " + potatoe + " " + potatoeLifetimeFactor, adress);
                            }

                            potatoe = 0;
                        } else {
                            try {
                                double accelX = accelerometer.getAccelX();

                                if (accelX > 2 || accelX < -2) {

                                    main.sendConnectionMessage(POTATOE + " " + potatoe+ " " + potatoeLifetimeFactor, adress);
                                    currentState = WAITINGFORPOTATOE;
                                    potatoe = 0;
                                }
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                        }
                    }
                }
            }
        } else {
            currentState = INITIAL;
            potatoe = 0;
            main.resetConnections();
        }
        display();
    }

    private String generateRandomAdress() {
        Random r = new Random();
        Connection con = (Connection) main.getActiveConnections().elementAt((int) (r.nextDouble() * main.getActiveConnections().size()));
        String adress = con.getAddress();

        return adress;
    }

    /**
     * handles recieving of messages
     * @param message
     */
    public void receiveMessage(String message, String addressNumber) {
        String[] parts = main.separateStrings(message);
        int protocolNumber = Integer.parseInt(parts[0]);

        oldState = currentState;
        
        switch(protocolNumber){
            case STARTGAME:
                currentState = WAITINGFORPOTATOE;
                break;
            case POTATOE:
                System.out.println("got potatoe");
                if(currentState != LOSER) {
                    currentState = HASPOTATOE;
                    potatoe = Long.parseLong(parts[1]);
                    potatoeLifetimeFactor =Integer.parseInt(parts[2]);
                    receiveTime = System.currentTimeMillis();             
                }
                break;
            case DEADPLAYER:
                main.setConnectionToIdle(addressNumber);              
                break;
            case NEWROUND:
                main.resetConnections();
                break;
            case WAITFORSTART:
                currentState = WAIT;
                break;
            case ARE_YOU_THERE:
                main.sendConnectionMessage(I_AM_HERE + "", addressNumber);
                break;
        }
    }

    /**
     * generates an endtime
     * @return the timestamp from current time + time for a potato to end
     */
    private long generatePotatoeLifeTime() {
        Random r = new Random();
        long random = 0;
        
        while(random < (potatoeLifetimeFactor / 2) ){
            random = r.nextInt(potatoeLifetimeFactor);
        }

        return System.currentTimeMillis() + random;
    }

    public int getScore() {
        return score;
    }

    public void switchPressed(ISwitch sw) {
        if(leftSwitch.isClosed() && rightSwitch.isClosed()) {
            switch(currentState) {
                case CHOOSEPOTATOELIFETIME:
                    currentState = HASPOTATOE;
                    main.massMessage(""+STARTGAME);
                    potatoe = generatePotatoeLifeTime();
                    main.resetConnections();
                    break;
            }
        } else if(sw == leftSwitch) {
            switch(currentState){
                          
                case CHOOSEPOTATOELIFETIME:
                    if(potatoeLifetimeFactor > 10000) {
                        potatoeLifetimeFactor-=10000;
                    }
                    potatoe = generatePotatoeLifeTime();
                    break;
                case INITIAL:
                    currentState = CHOOSEPOTATOELIFETIME;
                    main.massMessage(""+WAITFORSTART);
                    break;
                case WINNER:
                    main.massMessage(""+NEWROUND);
                    currentState = CHOOSEPOTATOELIFETIME;
                    potatoeLifetimeFactor = 10000;
                    break;
            }
        } else if(sw == rightSwitch) {
       
            switch(currentState){

                case CHOOSEPOTATOELIFETIME:
                    if(potatoeLifetimeFactor < 80000) {
                        potatoeLifetimeFactor+=10000;
                    }
                    potatoe = generatePotatoeLifeTime();
                    break;
                case INITIAL:
                    currentState = CHOOSEPOTATOELIFETIME;
                    main.massMessage(""+WAITFORSTART);
                    break;
                case WINNER:
                    main.massMessage(""+NEWROUND);
                    currentState = CHOOSEPOTATOELIFETIME;
                    potatoeLifetimeFactor = 10000;
                    break;
            }
        }
    }

    public void switchReleased(ISwitch sw) {
    }
}
